package com.powerband.apiheartrate.manager

import android.app.Application
import com.powerband.apiheartrate.ble.fbkBleController.FBKBleController
import com.powerband.apiheartrate.ble.fbkBleController.FBKBleControllerCallBack
import com.powerband.apiheartrate.ble.fbkBleDevice.FBKBleDeviceStatus
import com.powerband.apiheartrate.ble.fbkBleDevice.FBKBleUuids
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothDevice
import com.powerband.apiheartrate.base.BatteryStatus
import com.powerband.apiheartrate.base.FBKArmBandCmd
import com.powerband.apiheartrate.base.FBKDeviceMode
import com.powerband.apiheartrate.base.FBKSummaryType
import com.powerband.apiheartrate.ble.fbkBleDevice.FBKBleDevice
import com.powerband.apiheartrate.ota.BleOtaCallback
import com.powerband.apiheartrate.ota.BleOtaManager
import com.powerband.apiheartrate.ota.OtaError
import com.powerband.apiheartrate.ota.OtaStatus
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat

class FBKManagerController(
    context: Application,
    val mManagerControllerCallBack: FBKManagerControllerCallBack
) {
    private var mIsConnected = java.lang.Boolean.valueOf(false)
    private val mManagerCmd = FBKManagerCmd()
    private val mBleControllerCallBack: FBKBleControllerCallBack =
        object : FBKBleControllerCallBack {
            override fun onFinishDiscovery() {
                mManagerControllerCallBack.onFinishDiscovery()
            }

            override fun onDiscoveryDevice(result: FBKBleDevice) {
                mManagerControllerCallBack.onDiscoveryDevice(result)
            }

            override fun bleConnectError(error: String?) {
                mManagerControllerCallBack.bleConnectError(error, this@FBKManagerController)
            }

            override fun bleScanError(error: String?) {
                mManagerControllerCallBack.bleScanError(error, this@FBKManagerController)
            }

            override fun bleConnectStatus(connectStatus: FBKBleDeviceStatus?) {
                mIsConnected = isManagerBleConnected(connectStatus)
                mManagerControllerCallBack.bleConnectStatus(
                    connectStatus, this@FBKManagerController
                )
            }

            override fun bleConnectStatusLog(logString: String?) {
                mManagerControllerCallBack.bleConnectStatusLog(logString, this@FBKManagerController)
            }

            override fun bleWriteDataResult(isSucceed: Boolean) {}
            override fun bleConnectResult(characteristic: BluetoothGattCharacteristic) { //mapCharacterResult(characteristic)
            }

            override fun bleReceivedResult(type: FBKArmBandCmd, data: ByteArray?) {
                if (data == null) {
                    mManagerControllerCallBack.bleConnectError("received wrong data",this@FBKManagerController)
                    return
                }
               resultCallBack(data, type)
            }
            override fun bleConnectInfo(information: String?) {
                mManagerControllerCallBack.bleConnectInfo(information, this@FBKManagerController)
            }

            override fun bleConnectUuids(
                charUuidArray: List<BluetoothGattCharacteristic>?
            ) {
                mManagerControllerCallBack.bleConnectUuids(
                    charUuidArray,
                    this@FBKManagerController
                )
            }

            override fun bleDidWriteValue(data: ByteArray?) {
                mOtaMgr.bleDidWriteValue(data)
            }

            override fun bleDidReadValue(data: ByteArray?) {
                mOtaMgr.bleDidReadValue(data)
            }

            override fun bleSummaryInfo(info: List<Map<String, Any>>, type: FBKSummaryType) {
                mManagerControllerCallBack.bleSummaryInfo(info, type)
            }

            override fun logOutBufferData(data: List<Byte>) {
                mManagerControllerCallBack.logOutBufferData(data)
            }

            override fun requestTime() {
                syncTime()
            }

            override fun totalPacket(num: Int) {
                mManagerControllerCallBack.totalPacket(num)
            }
        }
    private var mBleController = FBKBleController(context, mBleControllerCallBack)
    val bluetoothDevice: BluetoothDevice?
        get() = mBleController.bluetoothDeviceInternal
    val blueConnected: Boolean?
    get() = mIsConnected

    fun startScan(timeOut: Long?) {
        mBleController.startScan(timeOut)
    }

    fun stopScan() {
        mBleController.stopScan()
    }

    fun connectBluetooth(bluetoothDevice: BluetoothDevice?, retryTime: Int? = 0) {
        mBleController.connectBluetooth(bluetoothDevice!!, retryTime)
    }

    fun connectBluetooth(macAddress: String?,retryTime: Int? = 0) {
        mBleController.connectBluetooth(macAddress!!,retryTime)
    }

    fun disconnectBle() {
        mBleController.disconnectBle()
    }

    fun registerBleListenerReceiver() {
        mBleController.registerBleListenerReceiver()
    }

    fun unregisterBleListenerReceiver() {
        mBleController.unregisterBleListenerReceiver()
    }
    fun readCharacteristicValueby(type: FBKArmBandCmd) {
        if (!mIsConnected) {
            mManagerControllerCallBack.bleConnectError("Bluetooth is disconnected", this)
            return
        }
        mBleController.readCharacteristicValueby(type)
    }
    fun toggleNotifyWith(status: Boolean, type: FBKArmBandCmd = FBKArmBandCmd.HeartRate) {
        if (!mIsConnected) {
            mManagerControllerCallBack.bleConnectError("Bluetooth is disconnected", this)
            return
        }
        mBleController.toggleNotifyWith(status, type)
    }
    fun getDeviceSerial() {
        mBleController.writeToBle(mManagerCmd.serialNo)
    }

    fun getDeviceStepFrequency() {
        mBleController.writeToBle(mManagerCmd.stepFrequency)
    }

    fun getRealTimeOxygen() {
        mBleController.writeToBle(mManagerCmd.bloodOxygen)
    }

    fun syncTime() {
        mBleController.writeToBle(mManagerCmd.syncTime())
    }

    fun queryBatteryStatus() {
       mBleController.writeToBle(mManagerCmd.batteryState)
    }


    fun queryDeviceMode() {
        mBleController.writeToBle(mManagerCmd.devieMode)
    }

    fun switchDevieMode(mode: FBKDeviceMode) {
        mBleController.writeToBle(mManagerCmd.switchMode + if (mode == FBKDeviceMode.Daily) 0 else 1)
    }

    fun setDeviceThreshold(min: Int,max: Int) {
        mBleController.writeToBle(
            mManagerCmd.maxThreshold(min.toByte(),max.toByte())
        )
    }

    fun requestCurrentTime() {
        mBleController.writeToBle(mManagerCmd.bandTime)
    }

    fun keepSportAlive() {
        mBleController.writeToBle(mManagerCmd.keepAlive)
    }

    fun qureySportModeDetail() {
        mBleController.writeToBle(mManagerCmd.sportDetail)
    }

    fun lightSwitch(on: Boolean) {
        mBleController.writeToBle(mManagerCmd.lightCmd(on))
    }

    fun setDoNotDisturbTime(enable: Boolean, startHour: Int, startMin: Int, endHour: Int, endMin: Int) {
        mBleController.writeToBle(mManagerCmd.disturbData(enable, startHour, startMin, endHour, endMin),)
    }
    fun getSummaryHeartRate(startDateStamp: Long, endDateStamp: Long) {
        mBleController.getSummaryData(startDateStamp,endDateStamp,FBKSummaryType.HeartRate)
    }

    fun getSummarySteps(startDateStamp: Long, endDateStamp: Long) {
        mBleController.getSummaryData(startDateStamp,endDateStamp,FBKSummaryType.Step)
    }
    fun getSummaryBloodOxygen(startDateStamp: Long, endDateStamp: Long) {
        mBleController.getSummaryData(startDateStamp,endDateStamp,FBKSummaryType.Oxgen)
    }
    fun getSummaryPressureIndex(startDateStamp: Long, endDateStamp: Long) {
        mBleController.getSummaryData(startDateStamp,endDateStamp,FBKSummaryType.Pressure)
    }
    fun getSummaryCalorieInfo(startDateStamp: Long, endDateStamp: Long) {
        mBleController.getSummaryData(startDateStamp,endDateStamp,FBKSummaryType.Calorie)
    }
    fun getSummarySleep(startDateStamp: Long, endDateStamp: Long) {
        mBleController.getSummaryData(startDateStamp,endDateStamp,FBKSummaryType.Sleep)
    }
    fun getExerciseData(startDateStamp: Long, endDateStamp: Long) {
        mBleController.getSummaryData(startDateStamp,endDateStamp,FBKSummaryType.Sport)
    }

    fun getMotionData(pageSize: Int, sportMode:Boolean) {
        mBleController.getMotionData(pageSize, sportMode)
    }

    fun updateSeq(sportMode:Boolean) {
        mBleController.updateSeq(sportMode)
    }

    private val mOtaMgr = BleOtaManager(object : BleOtaCallback{
        override fun sendData(data: ByteArray) {
            mBleController.sendOTAData(data)
        }

        override fun otaLog(status: OtaStatus, progress: Float) {
            mManagerControllerCallBack.otaLog(status,progress)
//            if (progress >= 100F) {
//                mBleController.disconnectBle()
//            }
        }

        override fun otaError(error: OtaError) {
            mManagerControllerCallBack.otaError(error)
        }

        override fun readOtaChar() {
            mBleController.readOTAData()
        }

    })

    fun resetFactory() {
        mBleController.writeToBle(mManagerCmd.resetFactory)
    }

    fun forseSleepOut() {
        mBleController.writeToBle(mManagerCmd.forseSleepOut)
    }
    fun startOTA(data: ByteArray?) {
        mOtaMgr.startOTA(data)
        //mBleController.toggleNotifyWith(false, FBKArmBandCmd.HeartRate)
    }
    private fun resultCallBack(value: ByteArray, type: FBKArmBandCmd) {
        mManagerControllerCallBack.bleConnectResult(value, type, this)
    }
    private fun isManagerBleConnected(connectStatus: FBKBleDeviceStatus?): Boolean {
        return connectStatus === FBKBleDeviceStatus.BleConnected
                || connectStatus === FBKBleDeviceStatus.Blesynchronizing
                || connectStatus === FBKBleDeviceStatus.BleSyncOver
    }

    companion object {
        private val TAG = FBKManagerController::class.java.simpleName
    }
}